﻿
#include "stdafx.h"
#include "colordef.h"
#include <ddraw.h>
#include "cpuinfo.h"
#include "color_mode.h"
#include "alphablend.h"

//#define ALPHA_X86_FULLLEVEL_C
//#define ALPHA_X86_32LEVEL_ASM
//#define ALPHA_MMX_FULLLEVEL_ASM
//#define ALPHA_MMX_32LEVEL_ASM
#define ALPHA_SSE_32LEVEL_ASM
//#define ALPHA_SSE2_32LEVEL_ASM
//#define ALPHA_MMX_INTEL_ASM

#pragma comment(lib, "dxguid.lib")
#pragma comment(lib, "ddraw.lib")

//////////////////////////////////////////////////////////////////////////

static DWORD				g_CpuCaps;		// CPU性能
static COLOR_MODE			g_ClrMode;		// 当前色彩模式
static BOOL					g_FullScr;		// 是否全屏显示
static BOOL					g_ClrCvt;		// 是否需要像素格式转换（决定是否使用画布表面）
static BOOL					g_Render;		// 是否执行渲染
static HWND					g_Wnd;			// 主窗口
static SIZE					g_Size;			// 绘图区域大小
static POINT				g_Point;		// 主窗口客户区起始屏幕坐标（即是主表面相对起始坐标）
static CRITICAL_SECTION		g_Lock;			// 该引擎大部分API都是不能同时执行的，故需加锁
static LPDIRECTDRAW7		g_DD;			// DirectDraw
static LPDIRECTDRAWSURFACE7	g_DDS;			// 主表面
static LPDIRECTDRAWSURFACE7	g_DDSBg;		// 背景表面（同主表面像素格式）
static LPDIRECTDRAWSURFACE7	g_DDSCanvas;	// 画布表面（R5G6B5固定）
static LPDIRECTDRAWCLIPPER	g_DDC;			// 窗口裁剪器

#ifdef SHOW_FPS
#define FPS_SAMPLE_MAX		400
static DWORD				g_FpsFrame;
static DWORD				g_SamleNum;
static QWORD				g_FpsSample[FPS_SAMPLE_MAX];
#endif

static BOOL NakedInitDD(HWND, BOOL);
static VOID NakedExitDD(VOID);
static BOOL NakedBeginDraw(VOID);
static BOOL NakedEndDraw(VOID);
static BOOL NakedFullScreen(BOOL);
static BOOL NakedDrawRectangle(LPCRECT, COLORREF);
static BOOL NakedDrawImage(LPCRECT, LPCVOID, UINT, LPCVOID, UINT);

static BOOL SetDisplayMode(BOOL);
static BOOL DetectColorMode(VOID);
static BOOL InitSurface(VOID);
static VOID ExitSurface(VOID);
static BOOL CreateCanvas(VOID);
static BOOL CreateClipper(VOID);
static BOOL RestoreAllSurface(VOID);
static BOOL RestoreSurface(LPDIRECTDRAWSURFACE7);
static VOID ClearScreen(VOID);
static BOOL FlipToBackground(LPDDSURFACEDESC2);
static BOOL ConvertPixelForamt(HDC, LPCVOID, INT, INT, UINT);
static VOID AlphaBlendRectangle(LPVOID, UINT, UINT, UINT, WORD, BYTE);
static VOID AlphaBlendImage(LPCVOID, UINT, LPVOID, UINT, LPCVOID, UINT, UINT, UINT);

//////////////////////////////////////////////////////////////////////////

BOOL InitDD(HWND hWnd, BOOL full_screen)
{
	BOOL ret;

	InitializeCriticalSection(&g_Lock);

	EnterCriticalSection(&g_Lock);
	ret = NakedInitDD(hWnd, full_screen);
	LeaveCriticalSection(&g_Lock);

	return ret;
}

VOID ExitDD(VOID)
{
	EnterCriticalSection(&g_Lock);
	NakedExitDD();
	LeaveCriticalSection(&g_Lock);

	DeleteCriticalSection(&g_Lock);
}

BOOL BeginDraw(VOID)
{
	BOOL ret;

	EnterCriticalSection(&g_Lock);
	ret = NakedBeginDraw();
	LeaveCriticalSection(&g_Lock);

	return ret;
}

BOOL EndDraw(VOID)
{
	BOOL ret;

	EnterCriticalSection(&g_Lock);
	ret = NakedEndDraw();
	LeaveCriticalSection(&g_Lock);

	return ret;
}

BOOL FullScreen(BOOL full_screen)
{
	BOOL ret;

	EnterCriticalSection(&g_Lock);
	ret = NakedFullScreen(full_screen);
	LeaveCriticalSection(&g_Lock);

	return ret;
}

BOOL DrawRectangle(LPCRECT pRect, COLORREF color)
{
	BOOL ret;

	EnterCriticalSection(&g_Lock);
	ret = NakedDrawRectangle(pRect, color);
	LeaveCriticalSection(&g_Lock);

	return ret;
}

BOOL DrawImage(LPCRECT pRect, LPCVOID pImage, UINT pitch, LPCVOID pAlpha, UINT ap)
{
	BOOL ret;

	EnterCriticalSection(&g_Lock);
	ret = NakedDrawImage(pRect, pImage, pitch, pAlpha, ap);
	LeaveCriticalSection(&g_Lock);

	return ret;
}

//////////////////////////////////////////////////////////////////////////

static BOOL NakedInitDD(HWND hWnd, BOOL full_screen)
{
	HRESULT hr;
	RECT rect;

	g_FullScr = full_screen;
	g_ClrCvt = FALSE;
	g_Render = FALSE;
	g_Wnd = hWnd;

	// 获取CPU性能参数
	g_CpuCaps = GetCpuCaps();

	if (!GetClientRect(g_Wnd, &rect))
		return FALSE;

	g_Size.cx = rect.right - rect.left;
	g_Size.cy = rect.bottom - rect.top;

	hr = DirectDrawCreateEx(NULL, reinterpret_cast<LPVOID *>(&g_DD), IID_IDirectDraw7, NULL);
	if (hr != DD_OK)
		return FALSE;

	// 设置显示模式
	if (!SetDisplayMode(g_FullScr))
		return FALSE;

	// 初始化所有表面
	if (!InitSurface())
		return FALSE;

	return TRUE;
}

static VOID NakedExitDD(VOID)
{
	ExitSurface();

	if (g_DD)
	{
		g_DD->Release();
		g_DD = NULL;
	}

	g_Size.cx = 0;
	g_Size.cy = 0;
	g_Wnd = NULL;
	g_FullScr = FALSE;
	g_ClrCvt = FALSE;
	g_Render = FALSE;
}

static BOOL NakedBeginDraw(VOID)
{
#ifdef SHOW_FPS
	union
	{
		FILETIME ft;
		QWORD dl;
	} ktime, utime;

	FILETIME dummy;
	GetThreadTimes(GetCurrentThread(), &dummy, &dummy, &ktime.ft, &utime.ft);

	QWORD time = ktime.dl / 10000 + utime.dl / 10000; // ns -> ms

	if (time < 300)
	{
		g_FpsFrame = 0;
		g_SamleNum = 0;
	}
	else
	{
		g_FpsSample[g_SamleNum] = time;

		if (++g_SamleNum >= FPS_SAMPLE_MAX)
			g_SamleNum = 0;

		g_FpsFrame++;
	}

#endif

	if (g_Render)
		return TRUE;

#ifndef TEST_ENGINE
	// 如果窗口没有显示则什么都不做
	if (!IsWindowVisible(g_Wnd) || IsIconic(g_Wnd))
		return TRUE;
#endif

	if (!RestoreAllSurface())
		return FALSE;

	g_Point.x = 0L;
	g_Point.y = 0L;

	if (!g_FullScr)
	{
		// 计算窗口客户区域起始绝对坐标
		if (!ClientToScreen(g_Wnd, &g_Point))
			return FALSE;
	}

	// 清屏（实际上只需要清掉画布）
	ClearScreen();

	g_Render = TRUE;
	return TRUE;
}

static BOOL NakedEndDraw(VOID)
{
	HRESULT hr;
	RECT rect;
	DDSURFACEDESC2 ddsd = { sizeof(ddsd) };

	if (!g_Render)
		return FALSE;

	g_Render = FALSE;

#ifndef TEST_ENGINE
	// 不是前景窗口，不理
	if (GetForegroundWindow() != g_Wnd)
		return TRUE;
#endif

	if (g_ClrCvt)
	{
		hr = g_DDSCanvas->Lock(NULL, &ddsd, DDLOCK_WAIT | DDLOCK_SURFACEMEMORYPTR, NULL);
		if (hr != DD_OK)
			return FALSE;

		if (!FlipToBackground(&ddsd))
		{
			g_DDSCanvas->Unlock(NULL);
			return FALSE;
		}

		hr = g_DDSCanvas->Unlock(NULL);
		if (hr != DD_OK)
			return FALSE;
	}

	rect.left = g_Point.x;
	rect.right = rect.left + g_Size.cx;
	rect.top = g_Point.y;
	rect.bottom = rect.top + g_Size.cy;

	// 将背景表面Blit到主表面
	hr = g_DDS->Blt(&rect, g_DDSBg, NULL, DDBLT_WAIT, NULL);
	if (hr != DD_OK)
		return FALSE;

#ifdef SHOW_FPS
	if (!g_FpsFrame)
		return TRUE;

	// 获得离屏表面的DC
	HDC hdc;
	if (g_DDS->GetDC(&hdc) != DD_OK)
		return TRUE;

	SetBkColor(hdc, RGB(0, 0, 0));
	if (g_FpsFrame < 100)
		SetTextColor(hdc, RGB(255, 0, 0));
	else if (g_FpsFrame < FPS_SAMPLE_MAX)
		SetTextColor(hdc, RGB(255, 255, 0));
	else
		SetTextColor(hdc, RGB(0, 255, 0));

	TCHAR fps[100];
	DOUBLE tmp = 0.0;

	if (g_FpsFrame == g_SamleNum || g_SamleNum == FPS_SAMPLE_MAX)
		tmp = static_cast<DOUBLE>(g_FpsSample[g_SamleNum - 1] - g_FpsSample[0]);
	else
		tmp = static_cast<DOUBLE>(g_FpsSample[g_SamleNum - 1] - g_FpsSample[g_SamleNum]);

	tmp = min(FPS_SAMPLE_MAX, g_FpsFrame) / tmp * 1000.0;

	_sntprintf(fps, 100, _T("fps : %.1f"), tmp);
	TextOut(hdc, g_Point.x, g_Point.y, fps, lstrlen(fps));

	g_DDS->ReleaseDC(hdc);
#endif
	return TRUE;
}

static BOOL NakedFullScreen(BOOL full_screen)
{
	RECT rect;
	DWORD style, exstyle;

	if (!g_DDS || !g_DD || !g_Wnd)
		return FALSE;

	if (!!g_FullScr == !!full_screen)
		return FALSE;

	// 重新设定显示模式
	if (!SetDisplayMode(full_screen))
		return FALSE;

	// 释放所有表面
	ExitSurface();

	// 全屏切换到窗口
	if (g_FullScr)
	{
		// 要恢复窗口大小
		rect.left = 0;
		rect.right = g_Size.cx;
		rect.top = 0;
		rect.bottom = g_Size.cy;
		style = GetWindowLong(g_Wnd, GWL_STYLE);
		exstyle = GetWindowLong(g_Wnd, GWL_EXSTYLE);
		if (AdjustWindowRectEx(&rect, style, !!GetMenu(g_Wnd), exstyle))
		{
			ShowWindow(g_Wnd, SW_RESTORE);
			SetWindowPos(g_Wnd, HWND_TOP, 0, 0, rect.right - rect.left, rect.bottom - rect.top, SWP_DEFERERASE | SWP_NOMOVE | SWP_SHOWWINDOW);
		}

		g_FullScr = FALSE;
	}
	// 窗口切换到全屏
	else
	{
		g_FullScr = TRUE;
	}

	// 重新创建所有表面
	InitSurface();

#ifdef SHOW_FPS
	g_FpsFrame = 0;
	g_SamleNum = 0;
#endif

	// 注意这里很重要！！！
	// 多线程环境中如果在BeginDraw和EndDraw之间调用这个函数切换全屏/窗口的话，
	// 这里必须终止掉Draw过程。
	// 这里将g_Render置FALSE与EndDraw有相同作用，但不会用到任何表面！
	g_Render = FALSE;

	return TRUE;
}

static BOOL NakedDrawRectangle(LPCRECT pRect, COLORREF color)
{
	BYTE alpha;
	WORD wColor;
	UINT width, height;
	HRESULT hr;
	DDSURFACEDESC2 ddsd = { sizeof(ddsd) };

	// 仅允许在BeginDraw和EndDraw间绘制
	if (!g_Render)
		return FALSE;

	if (!pRect || IsRectEmpty(pRect))
		return FALSE;

	// 全透明就不用画了
	alpha = GetAValue(color);
	if (!alpha)
		return TRUE;

	hr = g_DDSCanvas->Lock(const_cast<LPRECT>(pRect), &ddsd, DDLOCK_WAIT | DDLOCK_SURFACEMEMORYPTR, NULL);
	if (hr != DD_OK)
		return FALSE;

	if ((ddsd.dwFlags & DDSD_PITCH) && (ddsd.dwFlags & DDSD_WIDTH) && (ddsd.dwFlags & DDSD_HEIGHT))
	{
		wColor = COLOR_MAKERGB(GetRValue(color), GetGValue(color), GetBValue(color));
		width = min(ddsd.dwWidth, static_cast<DWORD>(pRect->right - pRect->left));
		height = min(ddsd.dwHeight, static_cast<DWORD>(pRect->bottom - pRect->top));

		AlphaBlendRectangle(ddsd.lpSurface, ddsd.lPitch, width, height, wColor, alpha);
	}

	hr = g_DDSCanvas->Unlock(NULL);
	if (hr != DD_OK)
		return FALSE;

	return TRUE;
}

static BOOL NakedDrawImage(LPCRECT pRect, LPCVOID pImage, UINT pitch, LPCVOID pAlpha, UINT ap)
{
	UINT width, height;
	HRESULT hr;
	DDSURFACEDESC2 ddsd = { sizeof(ddsd) };

	// 仅允许在BeginDraw和EndDraw间绘制
	if (!g_Render)
		return FALSE;

	if (!pImage || !pAlpha)
		return FALSE;

	if (!pRect || IsRectEmpty(pRect))
		return FALSE;

	// Pitch检查
	if (static_cast<INT>(ap) < pRect->right - pRect->left)
		return FALSE;

	hr = g_DDSCanvas->Lock(const_cast<LPRECT>(pRect), &ddsd, DDLOCK_WAIT | DDLOCK_SURFACEMEMORYPTR, NULL);
	if (hr != DD_OK)
		return FALSE;

	if ((ddsd.dwFlags & DDSD_PITCH) && (ddsd.dwFlags & DDSD_WIDTH) && (ddsd.dwFlags & DDSD_HEIGHT))
	{
		width = min(ddsd.dwWidth, static_cast<DWORD>(pRect->right - pRect->left));
		height = min(ddsd.dwHeight, static_cast<DWORD>(pRect->bottom - pRect->top));

		AlphaBlendImage(pImage, pitch, ddsd.lpSurface, ddsd.lPitch, pAlpha, ap, width, height);
	}

	hr = g_DDSCanvas->Unlock(NULL);
	if (hr != DD_OK)
		return FALSE;

	return TRUE;
}

//////////////////////////////////////////////////////////////////////////

static BOOL SetDisplayMode(BOOL full_screen)
{
	HRESULT hr;

	if (full_screen)
	{
		hr = g_DD->SetCooperativeLevel(g_Wnd, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
		if (hr != DD_OK)
			return FALSE;

		hr = g_DD->SetDisplayMode(g_Size.cx, g_Size.cy, COLOR_BITDEPTH, 0UL, 0UL);
		if (hr != DD_OK)
			return FALSE;
	}
	else
	{
		hr = g_DD->SetCooperativeLevel(g_Wnd, DDSCL_NORMAL);
		if (hr != DD_OK)
			return FALSE;
	}

	if (!DetectColorMode())
		return FALSE;

	return TRUE;
}

static BOOL DetectColorMode(VOID)
{
	HRESULT hr;
	DDSURFACEDESC2 ddsd = { sizeof(ddsd) };

	hr = g_DD->GetDisplayMode(&ddsd);
	if (hr != DD_OK)
		return FALSE;

	if (ddsd.ddpfPixelFormat.dwFlags != DDPF_RGB)
	{
		g_ClrMode = CM_UNKNOWN;
		g_ClrCvt = TRUE;
		return TRUE;
	}

	for (INT i = CM_UNKNOWN; i < CM_TOTALNUM; )
	{
		i++;

		if (ddsd.ddpfPixelFormat.dwRGBBitCount == CM_TABLE[i].bit_depth &&
			ddsd.ddpfPixelFormat.dwRBitMask == CM_TABLE[i].red_mask &&
			ddsd.ddpfPixelFormat.dwGBitMask == CM_TABLE[i].green_mask &&
			ddsd.ddpfPixelFormat.dwBBitMask == CM_TABLE[i].blue_mask)
		{
			g_ClrMode = static_cast<COLOR_MODE>(i);
			break;
		}
	}

	// 只有当前为R5G6B5的像素模式时才不需要做色深转换
	if (g_ClrMode == CM_R5G6B5)
		g_ClrCvt = FALSE;
	else
		g_ClrCvt = TRUE;

	return TRUE;
}

static BOOL InitSurface(VOID)
{
	HRESULT hr;
	DDSURFACEDESC2 ddsd = { sizeof(ddsd) };

	ddsd.dwFlags = DDSD_CAPS;
	ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
	ddsd.ddsCaps.dwCaps2 = 0UL;
	ddsd.ddsCaps.dwCaps3 = 0UL;
	ddsd.ddsCaps.dwCaps4 = 0UL;

	hr = g_DD->CreateSurface(&ddsd, &g_DDS, NULL);
	if (hr != DD_OK)
		return FALSE;

	ddsd.dwFlags |= DDSD_WIDTH | DDSD_HEIGHT;
	ddsd.dwWidth = g_Size.cx;
	ddsd.dwHeight = g_Size.cy;
	ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;

	// TODO: 这里是试出来的，原理不明，但明显快很多
	if (g_ClrCvt)
		ddsd.ddsCaps.dwCaps |= DDSCAPS_VIDEOMEMORY;
	else
		ddsd.ddsCaps.dwCaps |= DDSCAPS_SYSTEMMEMORY;

	hr = g_DD->CreateSurface(&ddsd, &g_DDSBg, NULL);
	if (hr != DD_OK)
		return FALSE;

	if (g_ClrCvt)
	{
		// 创建画布表面
		if (!CreateCanvas())
			return FALSE;
	}
	else
	{
		// 使用背景表面充当画布
		g_DDSCanvas = g_DDSBg;
		g_DDSCanvas->AddRef();
	}

	if (g_FullScr)
	{
		// 无窗口裁减
		g_DDC = NULL;
	}
	else
	{
		// 创建窗口裁减器
		if (!CreateClipper())
			return FALSE;
	}

	return TRUE;
}

static VOID ExitSurface(VOID)
{
	if (g_DDC)
	{
		g_DDC->Release();
		g_DDC = NULL;
	}

	if (g_DDSCanvas)
	{
		g_DDSCanvas->Release();
		g_DDSCanvas = NULL;
	}

	if (g_DDSBg)
	{
		g_DDSBg->Release();
		g_DDSBg = NULL;
	}

	if (g_DDS)
	{
		g_DDS->Release();
		g_DDS = NULL;
	}
}

static BOOL CreateCanvas(VOID)
{
	HRESULT hr;
	DDSURFACEDESC2 ddsd = { sizeof(ddsd) };

	// 由于后面要做色深转换，而读显存操作很慢，故建在内存里要快很多！！
	ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT;
	ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY;
	ddsd.ddsCaps.dwCaps2 = 0UL;
	ddsd.ddsCaps.dwCaps3 = 0UL;
	ddsd.ddsCaps.dwCaps4 = 0UL;
	ddsd.dwWidth = g_Size.cx;
	ddsd.dwHeight = g_Size.cy;
	ddsd.ddpfPixelFormat.dwSize = sizeof(ddsd.ddpfPixelFormat);
	ddsd.ddpfPixelFormat.dwFlags = DDPF_RGB;
	ddsd.ddpfPixelFormat.dwRGBBitCount = COLOR_BITDEPTH;
	ddsd.ddpfPixelFormat.dwRBitMask = COLOR_RMASK;
	ddsd.ddpfPixelFormat.dwGBitMask = COLOR_GMASK;
	ddsd.ddpfPixelFormat.dwBBitMask = COLOR_BMASK;
	ddsd.ddpfPixelFormat.dwRGBAlphaBitMask = 0UL;

	hr = g_DD->CreateSurface(&ddsd, &g_DDSCanvas, NULL);
	if (hr != DD_OK)
		return FALSE;

	return TRUE;
}

static BOOL CreateClipper(VOID)
{
	HRESULT hr;

	hr = DirectDrawCreateClipper(0UL, &g_DDC, NULL);
	if (hr != DD_OK)
		return FALSE;

	hr = g_DDC->SetHWnd(0UL, g_Wnd);
	if (hr != DD_OK)
		return FALSE;

	hr = g_DDS->SetClipper(g_DDC);
	if (hr != DD_OK)
		return FALSE;

	return TRUE;
}

static BOOL RestoreAllSurface(VOID)
{
	if (RestoreSurface(g_DDS) && RestoreSurface(g_DDSBg))
	{
		if (!g_ClrCvt || RestoreSurface(g_DDSCanvas))
			return TRUE;
	}

	// 如果无法恢复表面，有可能是窗口模式下用户更改了系统像素模式
	if (!g_FullScr)
	{
		// 需要先再次判断是否需要色深转换
		if (!DetectColorMode())
			return FALSE;

		// 此时尝试重建所有表面
		ExitSurface();
		if (InitSurface())
			return TRUE;
	}

	return FALSE;
}

static BOOL RestoreSurface(LPDIRECTDRAWSURFACE7 pDDS)
{
	HRESULT hr;

	hr = pDDS->IsLost();
	if (hr == DD_OK)
		return TRUE;

	// 如果表面丢失，尝试恢复
	hr = pDDS->Restore();
	if (hr != DD_OK)
		return FALSE;

	return TRUE;
}

static VOID ClearScreen(VOID)
{
	DDSURFACEDESC2 ddsd = { sizeof(ddsd), 0UL };
	DDBLTFX ddbfx = { sizeof(ddbfx) };

#ifndef TEST_ENGINE
	// 不是前景窗口，不理
	if (GetForegroundWindow() != g_Wnd)
		return;
#endif

	// 用这种方法清除表面
	ddbfx.dwFillColor = 0UL;
	g_DDSCanvas->Blt(NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_DONOTWAIT, &ddbfx);
}

static BOOL FlipToBackground(LPDDSURFACEDESC2 pDDSD)
{
	HRESULT hr;
	HDC hDC;
	DDSURFACEDESC2 ddsd = { sizeof(ddsd) };

	if (!(pDDSD->dwFlags & DDSD_PITCH))
		return FALSE;

	// 如果不支持优化，则使用GDI WINAPI进行默认转换（支持一切格式，但速度最慢）
	if (g_ClrMode <= CM_UNKNOWN || g_ClrMode >= CM_TOTALNUM)
	{
		// 锁住背景表面DC
		hr = g_DDSBg->GetDC(&hDC);
		if (hr != DD_OK)
			return FALSE;

		// 使用GDI设备无关位图完成像素格式自动转换
		ConvertPixelForamt(hDC, pDDSD->lpSurface, g_Size.cx, g_Size.cy, pDDSD->lPitch);

		// 解锁背景表面DC
		hr = g_DDSBg->ReleaseDC(hDC);
		if (hr != DD_OK)
			return FALSE;

		return TRUE;
	}

	hr = g_DDSBg->Lock(NULL, &ddsd, DDLOCK_WAIT | DDLOCK_SURFACEMEMORYPTR, NULL);
	if (hr != DD_OK)
		return FALSE;

	if (pDDSD->dwFlags & DDSD_PITCH)
	{
		switch (g_ClrMode)
		{
		case CM_A8R8G8B8:
			ConvertToA8R8G8B8(pDDSD->lpSurface, pDDSD->lPitch, ddsd.lpSurface, ddsd.lPitch, g_Size.cx, g_Size.cy);
			break;
		}
	}

	// 解锁背景表面DC
	hr = g_DDSBg->Unlock(NULL);
	if (hr != DD_OK)
		return FALSE;

	return TRUE;
}

static BOOL ConvertPixelForamt(HDC hDC, LPCVOID pData, INT nWidth, INT nHeight, UINT nPitch)
{
	// 定义转换所需数据结构
	BYTE aBmpInfo[sizeof(BITMAPINFOHEADER) + sizeof(DWORD) * 3];
	LPBITMAPINFO pBmpInfo = reinterpret_cast<LPBITMAPINFO>(&aBmpInfo);
	LPDWORD pPixelMask = reinterpret_cast<LPDWORD>(aBmpInfo + sizeof(BITMAPINFOHEADER));

	// 清空结构体内容
	ZeroMemory(aBmpInfo, sizeof(aBmpInfo));

	// 设置位图信息头
	pBmpInfo->bmiHeader.biSize = sizeof(pBmpInfo->bmiHeader);
	pBmpInfo->bmiHeader.biBitCount = COLOR_BITDEPTH;
	pBmpInfo->bmiHeader.biWidth = nPitch / 2;
	pBmpInfo->bmiHeader.biHeight = -nHeight;
	pBmpInfo->bmiHeader.biPlanes = 1;
	pBmpInfo->bmiHeader.biCompression = BI_BITFIELDS;

	// 设置像素格式掩码
	pPixelMask[0] = COLOR_RMASK;
	pPixelMask[1] = COLOR_GMASK;
	pPixelMask[2] = COLOR_BMASK;

	// 创建内存DC
	HDC hMemDC = CreateCompatibleDC(hDC);
	if (!hMemDC)
		return FALSE;

	BOOL bRet = FALSE;

	// 创建位图
	HBITMAP hBitmap = CreateDIBSection(hMemDC, pBmpInfo, DIB_RGB_COLORS, NULL, NULL, 0UL);
	if (hBitmap)
	{
		// 设置位图像素
		if (SetDIBits(hMemDC, hBitmap, 0U, nHeight, pData, pBmpInfo, DIB_RGB_COLORS) == nHeight)
		{
			// 将位图选入内存DC
			SelectObject(hMemDC, hBitmap);

			// 将含有位图的内存DC Blit到背景表面的DC上，使用GDI的功能完成色深的自动转换
			BitBlt(hDC, 0, 0, nWidth, nHeight, hMemDC, 0, 0, SRCCOPY);

			// 别忘了要这样释放上面建立的资源
			DeleteObject(hBitmap);

			bRet = TRUE;
		}
	}

	// 最后要销毁内存DC
	DeleteDC(hMemDC);
	return bRet;
}

static VOID AlphaBlendRectangle(LPVOID pImage, UINT pitch, UINT width, UINT height, WORD color, BYTE alpha)
{
#ifdef ALPHA_X86_FULLLEVEL_C

	// 256级ALPHA位移法，C语言
	AlphaBlendFullLevel(color, pImage, pitch, width, height, alpha);

#elif defined ALPHA_X86_32LEVEL_ASM

	// 32级ALPHA简化法，X86指令集，汇编
	AlphaBlend32LevelX86(color, pImage, pitch, width, height, alpha);

#elif defined ALPHA_MMX_FULLLEVEL_ASM

	// 256级ALPHA位移法，MMX指令集，汇编
	AlphaBlendFullLevelMMX(color, pImage, pitch, width, height, alpha);

#elif defined ALPHA_MMX_32LEVEL_ASM

	// 32级ALPHA简化法，MMX指令集，汇编
	AlphaBlend32LevelMMX(color, pImage, pitch, width, height, alpha);

#elif defined ALPHA_SSE_32LEVEL_ASM

	// 32级ALPHA简化法，SSE指令集，汇编
	AlphaBlend32LevelSSE(color, pImage, pitch, width, height, alpha);

#elif defined ALPHA_SSE2_32LEVEL_ASM

	// 32级ALPHA简化法，SSE指令集，汇编
	AlphaBlend32LevelSSE2(color, pImage, pitch, width, height, alpha);

#else

	// 标准ALPHA计算，C语言
	AlphaBlendStandard(color, pImage, pitch, width, height, alpha);

#endif
}

static VOID AlphaBlendImage(LPCVOID pImage, UINT pitch, LPVOID buf, UINT bp, LPCVOID alpha, UINT ap, UINT width, UINT height)
{
#ifdef ALPHA_X86_FULLLEVEL_C

	// 256级ALPHA位移法，C语言
	AlphaBlendFullLevel(pImage, pitch, buf, bp, alpha, ap, width, height);

#elif defined ALPHA_X86_32LEVEL_ASM

	// 32级ALPHA简化法，X86指令集，汇编
	AlphaBlend32LevelX86(pImage, pitch, buf, bp, alpha, ap, width, height);

#elif defined ALPHA_MMX_FULLLEVEL_ASM

	// 256级ALPHA位移法，MMX指令集，汇编
	AlphaBlendFullLevelMMX(pImage, pitch, buf, bp, alpha, ap, width, height);

#elif defined ALPHA_MMX_32LEVEL_ASM

	// 32级ALPHA简化法，MMX指令集，汇编
	AlphaBlend32LevelMMX(pImage, pitch, buf, bp, alpha, ap, width, height);

#elif defined ALPHA_SSE_32LEVEL_ASM

	// 32级ALPHA简化法，SSE指令集，汇编
	AlphaBlend32LevelSSE(pImage, pitch, buf, bp, alpha, ap, width, height);

#elif defined ALPHA_SSE2_32LEVEL_ASM

	// 32级ALPHA简化法，SSE2指令集，汇编
	AlphaBlend32LevelSSE2(pImage, pitch, buf, bp, alpha, ap, width, height);

#elif defined ALPHA_MMX_INTEL_ASM

	void ablend_565(
	LPWORD lpAlpha,UINT iAlpPitch, LPWORD lpSrc,UINT iSrcX, UINT iSrcY, UINT iSrcPitch,
	LPWORD lpDst, UINT iDstX, UINT iDstY, UINT iDstW, UINT iDstH, UINT iDstPitch);
	// 
	ablend_565((LPWORD)alpha, ap, (LPWORD)pImage, 0, 0, pitch, (LPWORD)buf, 0, 0, width, height, bp);

#else

	// 标准ALPHA计算，C语言
	AlphaBlendStandard(pImage, pitch, buf, bp, alpha, ap, width, height);

#endif
}

//////////////////////////////////////////////////////////////////////////
